﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;

namespace SimpleIR
{
	/// <summary>
	/// This class is used to represent all bytecode operations that take a scalar value on the eval stack and evaluate to a new value on the eval stack.
	/// </summary>
	public sealed class IREvalStackOp : IRByteCode
	{
		/// <summary>
		/// An array containing all the acceptable opcodes for this operation class (in order)
		/// </summary>
		public static readonly OpCode.Op[] AcceptableOps = { OpCode.Op.PrimEQ, OpCode.Op.Less, OpCode.Op.LessU, OpCode.Op.LessEQ, OpCode.Op.LessEQU, OpCode.Op.Greater, OpCode.Op.GreaterU, OpCode.Op.GreaterEQ, OpCode.Op.GreaterEQU, OpCode.Op.Add, OpCode.Op.AddU, OpCode.Op.Div, OpCode.Op.DivU, OpCode.Op.Mult, OpCode.Op.MultU, OpCode.Op.Neg, OpCode.Op.Rem, OpCode.Op.RemU, OpCode.Op.Sub, OpCode.Op.SubU, OpCode.Op.And, OpCode.Op.Or, OpCode.Op.Not, OpCode.Op.Shl, OpCode.Op.Shr, OpCode.Op.ShrU, OpCode.Op.Xor, OpCode.Op.DerefableEQ, OpCode.Op.NonNull, OpCode.Op.Pop, OpCode.Op.Dup };

		public IREvalStackOp(OpCode.Op opc, IRSourceLocation sloc)
			: base(opc, sloc)
		{
			Debug.Assert(AcceptableOps.Contains(opc));
		}

        public override string ToString()
		{
			switch(this.OperationCode)
			{
				case OpCode.Op.PrimEQ:
					return "ceq:     ";
				case OpCode.Op.Less:
					return "clt:     ";
				case OpCode.Op.LessU:
					return "cltu:    ";
				case OpCode.Op.LessEQ:
					return "cle:     ";
				case OpCode.Op.LessEQU:
					return "cleu:    ";
				case OpCode.Op.Greater:
					return "cgt:     ";
				case OpCode.Op.GreaterU:
					return "cgtu:    ";
				case OpCode.Op.GreaterEQ:
					return "cge:     ";
				case OpCode.Op.GreaterEQU:
					return "cgeu:    ";
				case OpCode.Op.Add:
					return "add:     ";
				case OpCode.Op.AddU:
					return "addu:    ";
				case OpCode.Op.Div:
					return "div:     ";
				case OpCode.Op.DivU:
					return "divu:    ";
				case OpCode.Op.Mult:
					return "mul:     ";
				case OpCode.Op.MultU:
					return "mulu:    ";
				case OpCode.Op.Neg:
					return "neg:     ";
				case OpCode.Op.Rem:
					return "rem:     ";
				case OpCode.Op.RemU:
					return "remu:    ";
				case OpCode.Op.Sub:
					return "sub:     ";
				case OpCode.Op.SubU:
					return "subu:    ";
				case OpCode.Op.And:
					return "and:     ";
				case OpCode.Op.Or:
					return "or:      ";
				case OpCode.Op.Not:
					return "not:     ";
				case OpCode.Op.Shl:
					return "shl:     ";
				case OpCode.Op.Shr:
					return "shr:     ";
				case OpCode.Op.ShrU:
					return "shru:    ";
				case OpCode.Op.Xor:
					return "xor:     ";
				case OpCode.Op.DerefableEQ:
					return "ceq*:    ";
				case OpCode.Op.NonNull:
					return "nonnull: ";
				case OpCode.Op.Pop:
					return "pop:     ";
				case OpCode.Op.Dup:
					return "dup:     ";
				default:
					return "--BAD OPCODE--";
			}
		}
	}
}
